/*Bibliotecas Utilizadas:*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>

/*Variáveis Globais:*/
int *n_aux;
double an, bn, tn;

/*Protótipo das funções:*/
void* a_f(void*);
double a(int);

void* b_f(void*);
double b(int);

void* t_f(void*);
double t(int);

double p(int);

double pi(int);

/*
*Função chamada na criação da thread que executará a função 'a' para calcular a sequência 'an'.
*Parâmetro:
*	-void* s: ponteiro void por onde o número de iterações do algoritmo é passado à thread,e consequentemente às funções.
*/
void* a_f(void* s)
{

    n_aux = (int*)s;
    an = a(n_aux[0]);

    pthread_exit(0);
}
/*
*Função recursiva que efetivamente calcula a sequência 'an'.
*Parâmetro:
*	-int n: número de iterações (recursivas) do algoritmo, usadas para o cálculo da sequência an.
*Retorno:
*	-double: retorna o valor da soma parcial de 'an' para um determinado valor de n (recebido como parâmetro).
*/
double a(int n)
{

    if(n == 0)
    {
        return 1;
    }
    else
    {
        return (a(n - 1) + b(n - 1))/2;
    }
}

/*
*Função chamada na criação da thread que executará a função 'b' para calcular a sequência 'bn'.
*Parâmetro:
*	-void* s: ponteiro void por onde o número de iterações do algoritmo é passado à thread,e consequentemente às funções.
*/
void* b_f(void* s)
{

    n_aux = (int*)s;
    bn = b(n_aux[0]);

    pthread_exit(0);
}
/*
*Função recursiva que efetivamente calcula a sequência 'bn'.
*Parâmetro:
*	-int n: número de iterações (recursivas) do algoritmo, usadas para o cálculo da sequência bn.
*Retorno:
*	-double: retorna o valor da soma parcial de 'bn' para um determinado valor de n (recebido como parâmetro).
*/
double b(int n)
{

    if(n == 0)
    {
        return 1/sqrt(2);
    }
    else
    {
        return sqrt(a(n - 1) * b(n - 1));
    }
}

/*
*Função chamada na criação da thread que executará a função 't' para calcular a sequência 'tn'.
*Parâmetro:
*	-void* s: ponteiro void por onde o número de iterações do algoritmo é passado à thread,e consequentemente às funções.
*/
void* t_f(void* s)
{

    n_aux = (int*)s;
    tn = t(n_aux[0]);

    pthread_exit(0);
}
/*
*Função recursiva que efetivamente calcula a sequência 'tn'.
*Parâmetro:
*	-int n: número de iterações (recursivas) do algoritmo, usadas para o cálculo da sequência tn.
*Retorno:
*	-double: retorna o valor da soma parcial de 'tn' para um determinado valor de n (recebido como parâmetro).
*/
double t(int n)
{

    if(n == 0)
    {
        return 0.25;
    }
    else
    {
        return t(n - 1) - p(n - 1) * pow(a(n - 1) - a(n), 2);
    }
}

/*
*Função recursiva que auxilia no calculo da sequência 'tn', calculando o valor da sequência 'pn' utilizada no calculo de cada 'tn'.
*Parâmetro:
*	-int n: número de iterações (recursivas) do algoritmo, usadas para o cálculo da sequência pn.
*Retorno:
*	-double: retorna o valor da soma parcial de 'pn' para um determinado valor de n (recebido como parâmetro).
*/
double p(int n)
{

    if(n == 0)
    {
        return 1;
    }
    else
    {
        return 2 * p(n - 1);
    }
}

/*Função que calcula o valor de pi a partir dos valores obtidos das somas das sequências 'an', 'bn' e 'tn' (variáveis globais).
*Parâmetro:
*	-int n: número de iterações (recursivas) do algoritmo, usadas para o cálculo do pi.
*Retorno:
*	-double: retorna o valor obtido de pi a partir dos somas das sequências 'an', 'bn' e 'tn'.
*/
double pi(int n)
{
    return pow(an + bn, 2)/(4 * tn);
}

void gaussLegendrePar(void){

    int n = 30; //NÚMERO DE ITERAÇÕES
    int i;
    int it[1];

    pthread_attr_t attr;

    pthread_t p_threads[3];

    it[0] = n;

    /*Criando e executando as threads*/
    pthread_create(&p_threads[0], NULL, &a_f, (void*) it);
    pthread_create(&p_threads[1], NULL, &b_f, (void*) it);
    pthread_create(&p_threads[2], NULL, &t_f, (void*) it);

    /*Esperando o termino das threads*/
    for(i=0; i<3; i++)
        pthread_join(p_threads[i], NULL);

    printf("%.6f\n", pi(n));
}
